﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class IRuningTimer : MonoBehaviour {

    private static GameObject _instance;
    private static bool _isInit = false;
    private static List<IRTimer> _runLists;
    private static Queue<IRTimer> _idleLists;
    private static Dictionary<string, IRTimer> _dict;

    private float _unscaledTime;

	// Update is called once per frame
	void Update () {
       
        _unscaledTime = Time.unscaledTime;
        if (_runLists.Count > 0)
        {
            int length = _runLists.Count;
            for (int i = 0; i < length; i++)
            {
                IRTimer t = _runLists[i];
                if (t.IsActive)
                {
                    t.Runing(_unscaledTime);
                }
                else
                {
                    _runLists.Remove(t);
                    _idleLists.Enqueue(t);
                    i--;
                    length--;
                }
            }
        }
        else
        {
            ActiveGo = false;
        }
        
	}
    /// <summary>
    /// 返回guid,,通过此guid可执行暂停和移除操作
    /// </summary>
    /// <param name="interval">执行间隔(秒)</param>
    /// <param name="callback">执行回调<key唯一guid，指定剩余次数></param>
    /// <param name="count">执行几次，默认一次， -1:无限次</param>
    /// <param name="delay">延时多少秒开始执行</param>
    /// <returns></returns>
    public static string Start(float interval, Action<string, int> callback, int count = 1, float delay = 0)
    {
        _Init();

        IRTimer t = _GetTime();
        t.Reset(interval, callback, count, delay);
        t.Start(Time.unscaledTime);
        _runLists.Add(t);
        return t.GUID;
    }

    public static void Remove(string guid)
    {
        if (!string.IsNullOrEmpty(guid))
        {
            IRTimer t = null;
            _dict.TryGetValue(guid, out t);
            if (t != null)
            {
                t.Destroy();
            }
        }
    }

    public static void Stop(string guid)
    {
        if (!string.IsNullOrEmpty(guid))
        {
            IRTimer t = null;
            _dict.TryGetValue(guid, out t);
            if (t != null)
            {
                t.Stop();
            }

        }
    }

    private static IRTimer _GetTime(string guid = "")
    {
        IRTimer t = null;
        if (string.IsNullOrEmpty(guid))
        {
            if (_idleLists.Count > 0)
            {
                t = _idleLists.Dequeue();
            }
            else
            {
                t = new IRTimer();
                _dict.Add(t.GUID, t);
            }
        }
        else
        {
            _dict.TryGetValue(guid, out t);
        }
        return t;
    }
    private static void _Init()
    {
        if (!_isInit)
        {
            GameObject go = new GameObject("RuningTimeGo");
            go.AddComponent<IRuningTimer>();
            GameObject.DontDestroyOnLoad(go);
            _isInit = true;
            _instance = go;

            _runLists = new List<IRTimer>();
            _idleLists = new Queue<IRTimer>();
            _dict = new Dictionary<string, IRTimer>();
        }
        else
        {
            ActiveGo = true;
        }
    }

    private static bool ActiveGo
    {
        get
        {
            if (_instance != null)
            {
                return _instance.activeSelf;
            }
            return false;
        }
        set
        {
            if (_instance != null && _instance.activeSelf != value)
            {
                _instance.SetActive(value);
            }
        }
    }

    public class IRTimer
    {
        private static long GUIDNUM = 1;
        private bool _isActive;
        private bool _isStop;
        private string _GUID;
        private float _delay;
        private float _interval;
        private int _count;
        private Action<string, int> _callback;

        private float _startTime;
        private float _nextTime;


        public IRTimer()
        {
            _GUID = (GUIDNUM++).ToString();
        }

        public void Reset(float interval, Action<string, int> callback, int count, float delay)
        {
            _isActive = true;
            _isStop = false;
            _delay = delay;
            _interval = interval;
            _count = count;
            _callback = callback;

            _startTime = 0;
            _nextTime = 0;
        }

        public void Start(float startTime)
        {
            _isActive = true;
            _isStop = false;
            _startTime = startTime;
            _nextTime = _startTime + _interval + _delay;
        }

        public void Runing(float curTime)
        {
            if (!_isStop)
            {
                if (curTime >= _nextTime)
                {
                    if (_count > 0)
                    {
                        _count--;
                    }
                    if (_callback != null)
                    {
                        _callback.Invoke(_GUID, _count);
                    }
                    _nextTime += _interval;
                    if (_count == 0)
                    {
                        Destroy();
                    }
                }
            }
        }

        public void Stop()
        {
            _isStop = true;
        }

        public void Destroy()
        {
            _callback = null;
            _isStop = false;
            _isActive = false;
            _interval = 0;
            _delay = 0;
            _startTime = 0;
            _nextTime = 0;
            _count = -1;
        }

        public string GUID
        {
            get
            {
                return _GUID;
            }
        }

        public bool IsActive
        {
            get
            {
                return _isActive;
            }
        }
        
    }



}

